﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Outlook.WorkItems.Extension.Controls.ReportService;
using Outlook.WorkItems.Extension.Controls.WSSTeam;
using Outlook.WorkItems.Extension.Manager;
using Outlook.WorkItems.Extension.Managers;

namespace Outlook.WorkItems.Extension.Controls
{
    public class TeamProjectNode : TreeNode
    {
        private readonly FolderNode _workItemsNode;
        public bool LoadFiles { get; set; }
        public string TeamServerUrl { get; set; }
        public string TeamProjectName { get; set; }
        private delegate void FillRportNodeDelegate(CatalogItem report, string reportServer);
        private delegate void FillDocumentLibrairyNodeDelegate(string title, string viewUrl);
        private delegate void FillFolderNodeDelegate(TreeNode parentNode, string title, string path);
        private delegate void FillFileNodeDelegate(TreeNode parentNode, string title, string path);
        public TfsTeamProjectCollection TeamServer { get; set; }
        public string ReportVersion { get; set; }

        public TeamProjectNode(FavoriteTeamProject favorite, bool loadReport, bool loadDocumentLibrairies, bool loadQueries, bool loadFiles)
        {
            Favorite = favorite;
            LoadFiles = loadFiles;
            TeamServerUrl = favorite.TeamServerUri;
            TeamProjectName = favorite.TeamProjectName;

            if (favorite.IsDefault)
            {
                ImageIndex = 5;
                SelectedImageIndex = 5;
            }
            else
            {
                ImageIndex = 1;
                SelectedImageIndex = 1;
            }
            Text = favorite.TeamProjectName;
            Name = favorite.TeamProjectName;
            Tag = favorite.TeamProjectName;

            TeamServer = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(Favorite.TeamServerUri));

            if (loadReport)
            {
                ThreadPool.QueueUserWorkItem(LoadReport, this);
            }
            if (loadDocumentLibrairies)
            {
                ThreadPool.QueueUserWorkItem(LoadDocumentLibrairies, this);
            }
            if (loadQueries)
            {
                //workItemsNode = new FolderNode("Work Items", null);
                //this.Nodes.Add(workItemsNode);

                ThreadPool.QueueUserWorkItem(LoadQueries, this);
            }
        }

        public TeamProjectNode(string projectName, bool loadReport, bool loadDocumentLibrairies, bool loadQueries, bool loadFiles)
        {
            LoadFiles = loadFiles;
            ImageIndex = 1;
            SelectedImageIndex = 1;

            Text = projectName;
            Tag = projectName;
            if (loadReport)
            {
                ThreadPool.QueueUserWorkItem(LoadReport, this);
            }
            if (loadDocumentLibrairies)
            {
                ThreadPool.QueueUserWorkItem(LoadDocumentLibrairies, this);
            }
            if (loadQueries)
            {
                _workItemsNode = new FolderNode("Work Items", null);
                Nodes.Add(_workItemsNode);

                ThreadPool.QueueUserWorkItem(LoadQueries, this);
            }
        }

        public TeamServerNode TeamServerNode
        {
            get
            {
                TreeNode currentNode = this;
                while (!(currentNode is TeamServerNode) && currentNode != null)
                {
                    currentNode = currentNode.Parent;
                }
                return currentNode as TeamServerNode;
            }
        }

        public FavoriteTeamProject Favorite { get; set; }

        #region Queries Node

        public event EventHandler QueriesLoaded;

        private void OnQueriesLoaded(EventArgs e)
        {
            EventHandler handler = QueriesLoaded;
            if (handler != null) handler(this, e);
        }

        public void LoadQueries(object state)
        {
            try
            {
                var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(Favorite.TeamServerUri));
                var store = tfs.GetService<WorkItemStore>();
                store.RefreshCache();
                var project = store.Projects[Favorite.TeamProjectName];
                var queryHierarchy = project.QueryHierarchy;

                foreach (var item in queryHierarchy)
                {
                    if (item is QueryFolder)
                    {
                        var queryFolder = (QueryFolder)item;
                        LoadQueries(queryFolder, this);
                    }
                    else
                    {
                        LoadQuery((Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition)item, _workItemsNode);
                    }
                }
                OnQueriesLoaded(new EventArgs());
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        public void LoadQueries(QueryFolder queryFolder, TreeNode parentNode)
        {
            Func<QueryFolder, TreeNode, FolderNode> createFolderNodeFunction = CreateFolderNode;

            var folderNode = (FolderNode)TreeView.Invoke(createFolderNodeFunction, queryFolder, parentNode);
            foreach (var item in queryFolder)
            {
                if (item is QueryFolder)
                    LoadQueries((QueryFolder)item, folderNode);
                else
                    LoadQuery((Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition)item, folderNode);
            }
        }

        public void LoadQuery(Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition item, FolderNode folderNode)
        {
            Action<Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition, FolderNode> createQueryNodeFunction = CreateQueryNode;

            this.TreeView.Invoke(createQueryNodeFunction, item, folderNode);
        }

        private void CreateQueryNode(Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition query, FolderNode parentNode)
        {
            var queryNode = new QueryNode(query);
            queryNode.Tag = query;
            parentNode.Nodes.Add(queryNode);
        }

        private FolderNode CreateFolderNode(QueryFolder queryFolder, TreeNode parentNode)
        {
            var folderNode = new FolderNode(queryFolder.Name, null) { Tag = queryFolder };
            parentNode.Nodes.Add(folderNode);

            return folderNode;
        }

        #endregion

        #region Reporting Nodes

        public void LoadReport(object state)
        {

            var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(Favorite.TeamServerUri));
            var registration = (IRegistration)tfs.GetService(typeof(IRegistration));
            RegistrationEntry[] entries = registration.GetRegistrationEntries(RegistrationUtilities.RosettaName);

            string reportServer;
            string reportService = null;
            foreach (ServiceInterface si in entries[0].ServiceInterfaces)
            {
                if (si.Name == "ReportWebServiceUrl") // NEW : ReportWebServiceUrl ???
                    reportService = si.Url;
                else if (si.Name == "ReportsService")
                    reportService = si.Url;
            }


            if (reportService == null)
                return;
            reportServer = reportService.Substring(0, reportService.LastIndexOf('/'));
            FillReportsNodes(reportServer, reportService, Favorite.TeamProjectName);
        }

        private void FillReportsNodes(string reportServer, string reportService, string teamProjectName)
        {
            try
            {
                ReportingService2005 reporting = new ReportingService2005();
                //reporting.Url = "http://team.bewise.fr/ReportServer/ReportService2005.asmx";
                if (reportService.EndsWith("ReportService.asmx", StringComparison.InvariantCultureIgnoreCase))
                    reporting.Url = reportService.Substring(0, reportService.IndexOf("ReportService.asmx", StringComparison.InvariantCultureIgnoreCase)) + "ReportService2005.asmx";
                else
                    reporting.Url = reportService;

                reporting.UseDefaultCredentials = true;

                reporting.ServerInfoHeaderValue = new ServerInfoHeader();
                reporting.GetSystemProperties(null);

                ReportVersion = reporting.ServerInfoHeaderValue.ReportServerVersionNumber;

                string rootProjectPath;
                if (TeamServer.CatalogNode != null)
                {
                    rootProjectPath = "/TfsReports/" + TeamServer.CatalogNode.Resource.DisplayName + "/" + teamProjectName;
                }
                else
                {
                    rootProjectPath = "/" + teamProjectName;
                }
                CatalogItem[] items = reporting.ListChildren(rootProjectPath, true);

                foreach (var item in items)
                {
                    if (item.Type == ItemTypeEnum.Report)
                        TreeView.Invoke(new FillRportNodeDelegate(FillReportNode), item, reportServer);
                    else if (item.Type == ItemTypeEnum.Folder)
                        TreeView.Invoke(new FillRportNodeDelegate(FillReportNode), item, reportServer);
                }
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private void FillReportNode(CatalogItem item, string reportServer)
        {
            try
            {
                var result = TreeView.Nodes.FindNodes(tn => tn is FolderNode && tn.Tag.ToString() == item.Path.Substring(0, item.Path.LastIndexOf("/")));
                TreeNode parentNode;
                if (result != null && result.Count() == 1)
                    parentNode = result.ToList()[0];
                else
                    parentNode = this;

                if (item.Type == ItemTypeEnum.Report)
                    parentNode.Nodes.Add(new ReportNode(item, reportServer));
                else if (item.Type == ItemTypeEnum.Folder)
                    parentNode.Nodes.Add(new FolderNode(item.Name, item.Path));
            }
            catch (Exception ex)
            {
                using (ErrorForm frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        #endregion

        #region DocumentLibrairies Nodes

        public void LoadDocumentLibrairies(object state)
        {

            try
            {
                var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(Favorite.TeamServerUri));
                var registration = (IRegistration)tfs.GetService(typeof(IRegistration));
                var entries = registration.GetRegistrationEntries(RegistrationUtilities.SharePointName);

                string baseSiteUrl = null;
                foreach (ServiceInterface si in entries[0].ServiceInterfaces)
                {
                    if (si.Name == "BaseSiteUrl")
                        baseSiteUrl = si.Url;
                }
                
                string projectBaseUrl = baseSiteUrl + "/" + Favorite.TeamProjectName;
                string listsUri = projectBaseUrl + "/_vti_bin/Lists.asmx";

                var l = new Lists
                              {
                                  Url = listsUri, 
                                  UseDefaultCredentials = true
                              };
                XmlNode node = l.GetListCollection();
                XDocument xdoc = XDocument.Parse(node.OuterXml);
                XNamespace wssnamespace = xdoc.Root.GetDefaultNamespace();

                var libraries = from xnode in xdoc.Root.Elements(wssnamespace + "List")
                                where xnode.Attribute("BaseType").Value == "1" && xnode.Attribute("Hidden").Value == "False"
                                select xnode;

                foreach (var librairie in libraries)
                {
                    try
                    {
                        XmlDocument document = new XmlDocument();
                        XmlNode query = document.CreateElement("Query");
                        XmlNode viewFields = document.CreateElement("ViewFields");
                        XmlNode queryOptions = document.CreateElement("QueryOptions");
                        viewFields.InnerXml = "<FieldRef Name='ID' /><FieldRef Name='FSObjType' /><FieldRef Name='FileRef' /><FieldRef Name='FileLeafRef' />";
                        queryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><ViewAttributes Scope='RecursiveAll'/>";
                        //query.InnerXml = string.Concat(new object[] { "<Where> <Eq> <FieldRef Name='FSObjType'/><Value Type='Text'>1</Value></Eq> </Where>" });
                        XmlNode items = l.GetListItems(librairie.Attribute("Name").Value, string.Empty, query, viewFields, "10000", queryOptions, null);

                        TreeView.Invoke(new FillDocumentLibrairyNodeDelegate(FillDocumentLibrairies), librairie.Attribute("Title").Value, librairie.Attribute("DefaultViewUrl").Value);

                        //TreeNode treenode = new TreeNode(librairie.Attribute("Title").Value);
                        //treeView1.Nodes.Add(treenode);
                        TreeNode treenode = Nodes[Nodes.Count - 1];

                        XDocument xdoc2 = XDocument.Parse(items.OuterXml);

                        if (xdoc2.Root.Elements().Count() == 1)
                        {
                            List<string> paths = new List<string>();
                            IEnumerable<XElement> folders = xdoc2.Root.Elements().ToList()[0].Elements();
                            foreach (var folder in folders)
                            {
                                TreeNode currentNode = treenode;
                                string folderPath = folder.Attribute("ows_FileRef").Value;
                                string sItemType = folder.Attribute("ows_FSObjType").Value;
                                int itemType;
                                int.TryParse(sItemType.Substring(sItemType.Length - 1, 1), out itemType);
                                string[] splitPath = folderPath.Split('/');
                                string pathconcatenate = "";
                                string documentLibrairy = treenode.Tag.ToString().Substring(treenode.Tag.ToString().IndexOf("/", 7), treenode.Tag.ToString().Length - treenode.Tag.ToString().IndexOf("/", 7));
                                bool flag = false;

                                foreach (string s in splitPath)
                                {
                                    if (!flag)
                                    {
                                        flag = documentLibrairy.Contains(string.Format("/{0}/", s));
                                        pathconcatenate = s;
                                    }
                                    else
                                    {
                                        pathconcatenate += "/" + s;
                                        if (!paths.Contains(pathconcatenate))
                                        {
                                            // File
                                            if (itemType == 0)
                                            {
                                                if (s == splitPath[splitPath.Length - 1])
                                                {
                                                    if (LoadFiles)
                                                    {
                                                        string commonPath = baseSiteUrl.Substring(baseSiteUrl.IndexOf("/sites") + 1, baseSiteUrl.Length - baseSiteUrl.IndexOf("/sites") - 1);
                                                        //this.TreeView.Invoke(new FillFileNodeDelegate(FillFileNode), currentNode, s, pathconcatenate);
                                                        string filePath = folderPath;
                                                        if (filePath.Contains("#"))
                                                        {
                                                            filePath = filePath.Substring(filePath.IndexOf("#") + 1, filePath.Length - (filePath.IndexOf("#") + 1));
                                                        }
                                                        if (filePath.Contains(commonPath))
                                                        {
                                                            filePath = filePath.Replace(commonPath, "");
                                                        }
                                                        filePath = baseSiteUrl + filePath;
                                                        TreeView.Invoke(new FillFileNodeDelegate(FillFileNode), currentNode, s, filePath);
                                                        currentNode = currentNode.Nodes[currentNode.Nodes.Count - 1];
                                                        paths.Add(pathconcatenate);
                                                    }
                                                }
                                                //else
                                                //{
                                                //    this.TreeView.Invoke(new FillFolderNodeDelegate(FillFolderNode), currentNode, s, pathconcatenate);
                                                //    currentNode = currentNode.Nodes[currentNode.Nodes.Count - 1];
                                                //    paths.Add(pathconcatenate);
                                                //}
                                            }
                                            // Folder
                                            else if (itemType == 1 && !documentLibrairy.Contains(pathconcatenate))
                                            {
                                                TreeView.Invoke(new FillFolderNodeDelegate(FillFolderNode), currentNode, s, pathconcatenate);
                                                currentNode = currentNode.Nodes[currentNode.Nodes.Count - 1];
                                                paths.Add(pathconcatenate);
                                            }
                                        }
                                        else
                                        {
                                            foreach (TreeNode nodeFolder in currentNode.Nodes)
                                            {
                                                if (nodeFolder.Text == s)
                                                    currentNode = nodeFolder;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                }
            }
            catch { }
        }

        private void FillDocumentLibrairies(string title, string viewUrl)
        {
            try
            {
                Nodes.Add(new DocumentLibrairyNode(title, viewUrl));
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private void FillFolderNode(TreeNode parentNode, string title, string path)
        {
            try
            {
                parentNode.Nodes.Add(new FolderNode(title, path));
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private void FillFileNode(TreeNode parentNode, string title, string path)
        {
            try
            {
                parentNode.Nodes.Add(new FileNode(title, path, parentNode.TreeView.ImageList));
            }
            catch (Exception ex)
            {
                using (var frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        #endregion
    }

    public static class ReportingServicesVersion
    {
        public const string Reporting2008 = "2007.100.1600.22";
        public const string Reporting2005 = "2005.090.2047.00";
    }
}
